package org.xfy.ymcc.controller;

import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.BucketOrder;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedStringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.xfy.common.result.JsonResult;
import org.xfy.ymcc.domain.AggrPageList;
import org.xfy.ymcc.domain.AggrTermsBucket;
import org.xfy.ymcc.domain.CourseDoc;
import org.xfy.ymcc.dto.CourseDocQuery;
import org.xfy.ymcc.mapper.CourseElasticsearchRepository;
import org.xfy.ymcc.mapper.HighlightResultMapper;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/search")
public class SearchController {
    @Autowired
    private CourseElasticsearchRepository repository;
    @Autowired
    private ElasticsearchRestTemplate template;
    @Autowired
    private HighlightResultMapper highlightResultMapper;

    @PostMapping("/getCourse")
    public JsonResult getCourse(@RequestBody List<Long> courseIds){
        Iterable<CourseDoc> allById = repository.findAllById(courseIds);
        return JsonResult.success().setData(allById);
    }

    @PostMapping("/saveSearch")
    public JsonResult saveSearch(@RequestBody CourseDoc courseDoc) {
        repository.save(courseDoc);
        return JsonResult.success();
    }

    @PostMapping("/queryCourse")
    public JsonResult queryCourse(@RequestBody CourseDocQuery CourseDocQuery) {
        //第一层 query
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
        //bool组合多个条件
        BoolQueryBuilder bool = QueryBuilders.boolQuery();
        //高级查询底层都是通过单分支语句动态拼接条件
        if (StringUtils.hasText(CourseDocQuery.getKeyword())) {
            bool.filter().add(QueryBuilders.matchQuery("name", CourseDocQuery.getKeyword()));
        }
        if (CourseDocQuery.getPriceMin() != null) {
            bool.filter().add(QueryBuilders.rangeQuery("price").gte(CourseDocQuery.getPriceMin()));
        }
        if (CourseDocQuery.getPriceMax() != null) {
            bool.filter().add(QueryBuilders.rangeQuery("price").lte(CourseDocQuery.getPriceMax()));
        }
        queryBuilder.withQuery(bool);
        //分页  注意：SpringDataElasticsearch的当前页码是从0开始的
        Pageable pageable = PageRequest.of(CourseDocQuery.getPageNo() - 1, CourseDocQuery.getPageSize());
        queryBuilder.withPageable(pageable);

        if (StringUtils.hasText(CourseDocQuery.getOrderField())) {
            SortOrder sortOrder = SortOrder.ASC;
            if ("desc".equalsIgnoreCase(CourseDocQuery.getOrderType())) {
                sortOrder = SortOrder.DESC;
            }
            SortBuilder sortBuilder = SortBuilders.fieldSort(CourseDocQuery.getOrderField()).order(sortOrder);
            queryBuilder.withSort(sortBuilder);
        }
        HighlightBuilder.Field highlightField = new HighlightBuilder.Field("name")
                .preTags("<span style='color:red'>")
                .postTags("</span>");

        queryBuilder.withHighlightFields(highlightField);

        //聚合查询,按照机构名字聚合，安装数量倒排
        queryBuilder.addAggregation(AggregationBuilders
                .terms("tenantNameAgg") //聚合名字
                .field("tenantName")	//聚合的字段
        );//排序后取前20条
        //2.调用repository的search方法查询
        AggregatedPage<CourseDoc> page = template.queryForPage(queryBuilder.build(), CourseDoc.class, highlightResultMapper);
        Map<String, List<AggrTermsBucket>> aggrResult = getAggrResult(page);
        //Page<CourseDoc> page = repository.search(queryBuilder.build());
//        HashMap<String, Object> map = new HashMap<>();
//        map.put("total", page.getTotalElements());
//        map.put("rows", page.getContent());
        AggrPageList<CourseDoc> courseDocAggrPageList = new AggrPageList<>(page.getTotalElements(), page.getContent(), aggrResult);

        return JsonResult.success().setData(courseDocAggrPageList);
    }

    private Map<String, List<AggrTermsBucket>> getAggrResult(AggregatedPage<CourseDoc> page) {
        //用来封装聚合结果
        Map<String,List<AggrTermsBucket>> aggrMap = new HashMap<>();

        //遍历聚合结果
        Aggregations aggregations = page.getAggregations();

        Map<String, Aggregation> stringAggregationMap = aggregations.asMap();

        Set<Map.Entry<String, Aggregation>> entries = stringAggregationMap.entrySet();

        entries.forEach(e->{
            //集合的名字
            String key = e.getKey();
            //集合的值的处理
            ParsedStringTerms value = (ParsedStringTerms)e.getValue();
            List<? extends Terms.Bucket> buckets = value.getBuckets();

            //使用lomda 把  List<StringTerms.Bucket>  转成  List<AggrTermsVo>
            List<AggrTermsBucket> aggrTermsVos = buckets.stream().map(bucket -> {
                return new AggrTermsBucket(bucket.getKeyAsString(), bucket.getDocCount());
            }).collect(Collectors.toList());

            aggrMap.put(key, aggrTermsVos);
        });
        return aggrMap;
    }
}
